/* These are tests for Dequette candidates: tuple-like, array based or list-like
* mostly I'm interested in speed 
*/

package org.thewares.collection.test;

import org.scalatest.Spec;
import org.scalatest.matchers.ShouldMatchers;
import org.scalatest.prop.Checkers;

import org.thewares.collection.test.LittleDeques._;

object TestLittleDeque {

      class TestLittleDeque(td:Titled[LittleDeque[String]]) extends Spec with ShouldMatchers with Checkers {
	    val empty=td.empty;
	    println(td.title+"==========");

	    describe("A Deque") {
		  val nil:List[String]=Nil;

		  it("should be list like") {
			val q = 2 :: 1 :: empty;
			println("head is "+q.head +", q is "+q.toString)
			q.head should equal (2)
			q.tail.head should equal (1)
			def f(list:List[String]):Boolean={
			      var queue=(empty /: list) {case (q:LittleDeque[String],element:String) => element::q};
			      val full=queue;
			      var popped=nil;
			      for (i <- 1 to list.length){
				    popped = queue.head :: popped;
				    queue= queue.tail;
			      }
			      val ret=(popped==list);
			      if (ret==false){println("failing with: "+full+" is "+popped+" and "+list)};
			      ret
			}
			val range=1 to 20 toList;
			for (i <- range){
			      f(range.take(i).map(_.toString)) should equal (true);
			}
			check{lst:List[String] => f(lst.take(20))};
			      
		  }
	    }
      }

      // how fast is a list traversal?
      def listTraversals(){
	    val long= {1 to 100000 toList}.map(_.toString);
	    println("list traversals");
	    val ret=Timer.time(10,{var i=0; var z=0; while (i<10) { i=i+1; z =  long.drop(i*10000).length + z }; z.toString;});
	    println("10 list taversals: "+ret.timing);
	    val ret2=Timer.time(10,{var i=0; var z=0; while (i<110) { i=i+1; z =  long.drop(i*10000).length + z }; z.toString;});
	    println("110 list taversals: "+ret2.timing);
      }      

      def speed(td:Function0[Unit])={
	    td();
      }
      def sound(td:Function0[Unit])={
	    td(); //FIXME!
      }
      implicit def t1(t:Titled[LittleDeque[String]]):Function0[Unit]=new LittleTime(t); 
      implicit def t2(t:Titled[Deque[String]]):Function0[Unit]=new LittleBigTime(t); 
		
      def main(argv:Array[String]):Unit = {
	    val candidates:List[Function0[Unit]]=List(Titled[LittleDeque[String]]("Tuple-like",org.thewares.collection.test.LittleDeques.EmptyTup),
//				Titled[LittleDeque[String]]("Structure-like",org.thewares.collection.test.LittleDeques.EmptyLetter),
//				Titled[LittleDeque[String]]("ArrayBased2",org.thewares.collection.test.LittleDeques.EmptyB),
//				Titled[LittleDeque[String]]("ArrayBased1",org.thewares.collection.test.LittleDeques.EmptyA),
						     Titled[LittleDeque[String]]("LittleList",org.thewares.collection.test.LittleDeques.LittleList0),
						     Titled[Deque[String]]("FingerTree",finger.FingerTree.EmptySeq),
						     Titled[Deque[String]]("AlphaDeck",Deque.empty),
						     Titled[Deque[String]]("Eight",nodal.Nodes.EmptyEight)
//				Title//TitledDeque("Literature",Literature.EmptyCat)
			  );
//	    candidates.map(sound(_));
	    candidates.map(speed(_));
	    listTraversals;
      }
}

class LittleTime(td:Titled[LittleDeque[String]]) extends Function0[Unit]{
      val empty=td.empty;
      val range= 0 to 19 toList
      val long= {1 to 100000 toList}.map(_.toString);
      def apply()={
	    println("=-=-=-="+td.title)
	    for (i<- range){
		  val start=(empty /: range.take(i).map(_.toString)){(d,e) => e :: d}
		  val ret=Timer.time (10,{(start /: long){(d,e) => val x=e::d; x.tail}});
		  println(i+": "+ret.timing);
	    }
      }

}

class LittleBigTime(td:Titled[Deque[String]]) extends Function0[Unit]{
      val empty=td.empty;
      val range= 0 to 99 toList
      val long= {1 to 100000 toList}.map(_.toString);
      def apply()={
	    println("=-=-=-="+td.title)
	    for (i<- range){
		  val start=(empty /: range.take(i).map(_.toString)){(d,e) => e :: d}
		  val ret=Timer.time (10,{(start /: long){(d,e) => val x= e::d; x.tail}});
		  println(i+": "+ret.timing);
	    }
      }

}

